/* eslint-disable prefer-rest-params */
const stringWidth = require('string-width');
const MOVE_LEFT = Buffer.from('1b5b3130303044', 'hex').toString();
const MOVE_UP = Buffer.from('1b5b3141', 'hex').toString();
const CLEAR_LINE = Buffer.from('1b5b304b', 'hex').toString();

// const fs = require('fs');

/**
 * 可擦除的日志
 * @param {NodeJS.WriteStream} stream
 */
function ErasableLog(stream) {
  const writeRaw = stream.write;
  stream.write = write;

  const prev = {
    str: null,
    clear: '',
    line: 0,
  };

  /**
   * 重写日志数据流
   * @param {String} data
   */
  // eslint-disable-next-line no-unused-vars
  function write(data) {
    // fs.appendFileSync('./index.log', [data, JSON.stringify(prev), '\n'].join(','));
    if (prev.line > 0) {
      data = prev.clear + data + prev.str;
    }
    return writeRaw.apply(this, arguments);
  }

  if (stream === process.stderr || stream === process.stdout) {
    process.on('exit', () => {
      if (prev.str !== null) clear();
    });
  }

  /**
   * 可擦除的日志方法
   * @param  {...any} args
   */
  function log(...args) {
    prev.str = Array.prototype.join.call(args, ' ');
    prev.line = _getLineCount(prev.str);
    stream.write('');
    prev.clear = _getClearStr(prev.line);
  }

  log.clear = clear;
  log.reset = reset;

  /**
   * 获取擦除内容的字符串
   */
  function _getClearStr(lineCount) {
    let clearStr = '';
    for (let i = 0; i < lineCount; i += 1) {
      clearStr += MOVE_LEFT + CLEAR_LINE + (i < lineCount - 1 ? MOVE_UP : '');
    }
    return clearStr;
  }

  /**
   * 获取内容占用的长度
   * @param {*} str
   */
  function _getLineCount(str) {
    const lines = str.split('\n');
    let lineCount = 0;
    for (let i = 0; i < lines.length; i += 1) {
      lineCount += Math.ceil(stringWidth(lines[i]) / stream.columns) || 1;
    }
    return lineCount;
  }

  /**
   * 清除可擦除区域
   */
  function clear() {
    log('');
  }

  /**
   * 重置可擦除区域
   */
  function reset() {
    prev.str = '';
    prev.clear = '';
    prev.line = 0;
  }

  return log;
}

ErasableLog.stdout = ErasableLog(process.stdout);
ErasableLog.stderr = ErasableLog(process.stderr);

module.exports = ErasableLog;
